using System;
using System.Globalization;
using System.Runtime.InteropServices;
using PickGold.Charting;

namespace PickGold.Charting.Formulas
{
	internal class TimeSeriesAndForecasting : IFormula
	{
		private double[][] CopyDeterminant(double[][] inputDeterminant)
		{
			int length = inputDeterminant.GetLength(0);
			double[][] numArray = new double[length][];
			for (int i = 0; i < length; i++)
			{
				numArray[i] = new double[length];
			}
			for (int j = 0; j < length; j++)
			{
				for (int k = 0; k < length; k++)
				{
					numArray[j][k] = inputDeterminant[j][k];
				}
			}
			return numArray;
		}

		private double Determinant(double[][] inputDeterminant)
		{
			double num = 0.0;
			double num2 = 1.0;
			if (inputDeterminant.Length == 2)
			{
				return ((inputDeterminant[0][0] * inputDeterminant[1][1]) - (inputDeterminant[0][1] * inputDeterminant[1][0]));
			}
			for (int i = 0; i < inputDeterminant.GetLength(0); i++)
			{
				double[][] numArray = this.MakeSubDeterminant(inputDeterminant, i);
				num += (num2 * this.Determinant(numArray)) * inputDeterminant[i][0];
				num2 *= -1.0;
			}
			return num;
		}

		private void Forecasting(double[][] inputValues, out double[][] outputValues, string[] parameterList)
		{
			int num;
			int num2;
			bool flag;
			bool flag2;
			double[][] numArray;
			RegressionType polynomial = RegressionType.Polynomial;
			if (parameterList[0] == "Exponential")
			{
				polynomial = RegressionType.Exponential;
				num = 2;
			}
			else if (parameterList[0] == "Linear")
			{
				polynomial = RegressionType.Polynomial;
				num = 2;
			}
			else if (parameterList[0] == "IsLogarithmic")
			{
				polynomial = RegressionType.Logarithmic;
				num = 2;
			}
			else if (parameterList[0] == "Power")
			{
				polynomial = RegressionType.Power;
				num = 2;
			}
			else if ((parameterList.Length < 1) || !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out num))
			{
				num = 2;
			}
			if ((num > 5) || (num < 1))
			{
				throw new InvalidOperationException(SR.ExceptionForecastingDegreeInvalid);
			}
			if (num > inputValues[0].Length)
			{
				throw new InvalidOperationException(SR.ExceptionForecastingNotEnoughDataPoints(num.ToString(CultureInfo.InvariantCulture)));
			}
			if ((parameterList.Length < 2) || !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out num2))
			{
				num2 = inputValues[0].Length / 2;
			}
			if ((parameterList.Length < 3) || !bool.TryParse(parameterList[2], out flag))
			{
				flag = true;
			}
			if ((parameterList.Length < 4) || !bool.TryParse(parameterList[3], out flag2))
			{
				flag2 = true;
			}
			this.Regression(polynomial, inputValues, out numArray, num, num2);
			if (!flag2 && !flag)
			{
				outputValues = numArray;
			}
			else
			{
				double[][] numArray3;
				double[][] numArray2 = new double[][] { new double[inputValues[0].Length / 2], new double[inputValues[0].Length / 2] };
				for (int i = 0; i < (inputValues[0].Length / 2); i++)
				{
					numArray2[0][i] = inputValues[0][i];
					numArray2[1][i] = inputValues[1][i];
				}
				this.Regression(polynomial, numArray2, out numArray3, num, inputValues[0].Length / 2);
				double d = 0.0;
				for (int j = inputValues[0].Length / 2; j < numArray3[1].Length; j++)
				{
					d += (numArray3[1][j] - inputValues[1][j]) * (numArray3[1][j] - inputValues[1][j]);
				}
				d /= (double)(inputValues[0].Length - (inputValues[0].Length / 2));
				d = Math.Sqrt(d) / ((double)(inputValues[0].Length / 4));
				double num6 = 0.0;
				for (int k = 0; k < inputValues[0].Length; k++)
				{
					num6 += (numArray[1][k] - inputValues[1][k]) * (numArray[1][k] - inputValues[1][k]);
				}
				num6 /= (double)inputValues[0].Length;
				num6 = Math.Sqrt(num6);
				outputValues = new double[][] { numArray[0], numArray[1], new double[numArray[0].Length], new double[numArray[0].Length] };
				if (!flag)
				{
					num6 = 0.0;
				}
				if (!flag2)
				{
					d = 0.0;
				}
				for (int m = 0; m < inputValues[0].Length; m++)
				{
					outputValues[2][m] = numArray[1][m] + (2.0 * num6);
					outputValues[3][m] = numArray[1][m] - (2.0 * num6);
				}
				double num9 = 0.0;
				for (int n = inputValues[0].Length; n < numArray[0].Length; n++)
				{
					num9 += d;
					outputValues[2][n] = (numArray[1][n] + num9) + (2.0 * num6);
					outputValues[3][n] = (numArray[1][n] - num9) - (2.0 * num6);
				}
			}
		}

		public virtual void Formula(string formulaName, double[][] inputValues, out double[][] outputValues, string[] parameterList, string[] extraParameterList, out string[][] outLabels)
		{
			string name = formulaName.ToUpper(CultureInfo.InvariantCulture);
			outLabels = null;
			try
			{
				string str2;
				if (((str2 = name) != null) && (str2 == "FORECASTING"))
				{
					this.Forecasting(inputValues, out outputValues, parameterList);
				}
				else
				{
					outputValues = null;
				}
			}
			catch (IndexOutOfRangeException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaInvalidPeriod(name));
			}
			catch (OverflowException)
			{
				throw new InvalidOperationException(SR.ExceptionFormulaNotEnoughDataPoints(name));
			}
		}

		private double[][] MakeSubDeterminant(double[][] inputDeterminant, int columnPos)
		{
			int length = inputDeterminant.GetLength(0);
			double[][] numArray = new double[length - 1][];
			for (int i = 0; i < (length - 1); i++)
			{
				numArray[i] = new double[length - 1];
			}
			int index = 0;
			for (int j = 0; j < length; j++)
			{
				if (j != columnPos)
				{
					for (int k = 1; k < length; k++)
					{
						numArray[index][k - 1] = inputDeterminant[j][k];
					}
					index++;
				}
			}
			return numArray;
		}

		private void PolynomialRegression(RegressionType regressionType, double[][] inputValues, out double[][] outputValues, int polynomialDegree, int forecastingPeriod, double logInterval)
		{
			double[] numArray = new double[polynomialDegree];
			int length = inputValues[0].Length;
			double maxValue = double.MaxValue;
			double num3 = 1.0;
			num3 = Math.Abs((double)(inputValues[0][0] - inputValues[0][inputValues[0].Length - 1])) / ((double)(inputValues[0].Length - 1));
			if (num3 <= 0.0)
			{
				num3 = 1.0;
			}
			if (regressionType != RegressionType.Logarithmic)
			{
				for (int m = 0; m < inputValues[0].Length; m++)
				{
					if (maxValue > inputValues[0][m])
					{
						maxValue = inputValues[0][m];
					}
				}
				for (int n = 0; n < inputValues[0].Length; n++)
				{
					inputValues[0][n] -= maxValue - 1.0;
				}
			}
			if (regressionType == RegressionType.Power)
			{
				for (int num6 = 0; num6 < inputValues[0].Length; num6++)
				{
					inputValues[0][num6] = Math.Log(inputValues[0][num6]);
					inputValues[1][num6] = Math.Log(inputValues[1][num6]);
				}
			}
			double[][] inputDeterminant = new double[polynomialDegree][];
			for (int i = 0; i < polynomialDegree; i++)
			{
				inputDeterminant[i] = new double[polynomialDegree];
			}
			for (int j = 0; j < polynomialDegree; j++)
			{
				for (int num9 = 0; num9 < polynomialDegree; num9++)
				{
					inputDeterminant[num9][j] = 0.0;
					for (int num10 = 0; num10 < inputValues[0].Length; num10++)
					{
						inputDeterminant[num9][j] += Math.Pow(inputValues[0][num10], (double)(num9 + j));
					}
				}
			}
			double num11 = this.Determinant(inputDeterminant);
			for (int k = 0; k < polynomialDegree; k++)
			{
				double[][] numArray3 = this.CopyDeterminant(inputDeterminant);
				for (int num13 = 0; num13 < polynomialDegree; num13++)
				{
					numArray3[k][num13] = 0.0;
					for (int num14 = 0; num14 < inputValues[0].Length; num14++)
					{
						numArray3[k][num13] += inputValues[1][num14] * Math.Pow(inputValues[0][num14], (double)num13);
					}
				}
				numArray[k] = this.Determinant(numArray3) / num11;
			}
			outputValues = new double[][] { new double[length + forecastingPeriod], new double[length + forecastingPeriod] };
			if (regressionType == RegressionType.Polynomial)
			{
				for (int num15 = 0; num15 < (length + forecastingPeriod); num15++)
				{
					outputValues[0][num15] = inputValues[0][0] + (num15 * num3);
					outputValues[1][num15] = 0.0;
					for (int num16 = 0; num16 < polynomialDegree; num16++)
					{
						outputValues[1][num15] += numArray[num16] * Math.Pow(outputValues[0][num15], (double)num16);
					}
				}
			}
			else if (regressionType == RegressionType.Exponential)
			{
				for (int num17 = 0; num17 < (length + forecastingPeriod); num17++)
				{
					outputValues[0][num17] = inputValues[0][0] + (num17 * num3);
					outputValues[1][num17] = Math.Exp(numArray[0]) * Math.Exp(numArray[1] * outputValues[0][num17]);
				}
			}
			else if (regressionType == RegressionType.Logarithmic)
			{
				for (int num18 = 0; num18 < (length + forecastingPeriod); num18++)
				{
					outputValues[0][num18] = Math.Exp(inputValues[0][0]) + (num18 * logInterval);
					outputValues[1][num18] = (numArray[1] * Math.Log(outputValues[0][num18])) + numArray[0];
				}
			}
			else if (regressionType == RegressionType.Power)
			{
				for (int num19 = 0; num19 < (length + forecastingPeriod); num19++)
				{
					outputValues[0][num19] = Math.Exp(inputValues[0][0]) + (num19 * logInterval);
					outputValues[1][num19] = Math.Exp(numArray[0]) * Math.Pow(outputValues[0][num19], numArray[1]);
				}
			}
			if (regressionType != RegressionType.Logarithmic)
			{
				for (int num20 = 0; num20 < (length + forecastingPeriod); num20++)
				{
					outputValues[0][num20] += maxValue - 1.0;
				}
			}
		}

		private void Regression(RegressionType regressionType, double[][] inputValues, out double[][] outputValues, int polynomialDegree, int forecastingPeriod)
		{
			if (regressionType == RegressionType.Exponential)
			{
				double[] numArray = new double[inputValues[1].Length];
				for (int i = 0; i < inputValues[1].Length; i++)
				{
					numArray[i] = inputValues[1][i];
					if (inputValues[1][i] <= 0.0)
					{
						throw new InvalidOperationException(SR.ExceptionForecastingExponentialRegressionHasZeroYValues);
					}
					inputValues[1][i] = Math.Log(inputValues[1][i]);
				}
				this.PolynomialRegression(regressionType, inputValues, out outputValues, 2, forecastingPeriod, 0.0);
				inputValues[1] = numArray;
			}
			else if (regressionType == RegressionType.Logarithmic)
			{
				double num3 = inputValues[0][0];
				double logInterval = Math.Abs((double)(inputValues[0][0] - inputValues[0][inputValues[0].Length - 1])) / ((double)(inputValues[0].Length - 1));
				if (logInterval <= 0.0)
				{
					logInterval = 1.0;
				}
				for (int j = 0; j < inputValues[0].Length; j++)
				{
					inputValues[0][j] = Math.Log(inputValues[0][j]);
				}
				this.PolynomialRegression(regressionType, inputValues, out outputValues, 2, forecastingPeriod, logInterval);
				for (int k = 0; k < outputValues[0].Length; k++)
				{
					outputValues[0][k] = num3 + (k * logInterval);
				}
			}
			else if (regressionType == RegressionType.Power)
			{
				double[] numArray2 = new double[inputValues[1].Length];
				double num7 = inputValues[0][0];
				for (int m = 0; m < inputValues[1].Length; m++)
				{
					numArray2[m] = inputValues[1][m];
					if (inputValues[1][m] <= 0.0)
					{
						throw new InvalidOperationException(SR.ExceptionForecastingPowerRegressionHasZeroYValues);
					}
				}
				double num6 = Math.Abs((double)(inputValues[0][0] - inputValues[0][inputValues[0].Length - 1])) / ((double)(inputValues[0].Length - 1));
				if (num6 <= 0.0)
				{
					num6 = 1.0;
				}
				this.PolynomialRegression(regressionType, inputValues, out outputValues, 2, forecastingPeriod, num6);
				inputValues[1] = numArray2;
				for (int n = 0; n < outputValues[0].Length; n++)
				{
					outputValues[0][n] = num7 + (n * num6);
				}
			}
			else
			{
				this.PolynomialRegression(regressionType, inputValues, out outputValues, polynomialDegree, forecastingPeriod, 0.0);
			}
		}

		public virtual string Name
		{
			get
			{
				return SR.FormulaNameTimeSeriesAndForecasting;
			}
		}

		internal enum RegressionType
		{
			Polynomial,
			Logarithmic,
			Power,
			Exponential
		}
	}
}

